use core::fmt::{Arguments, Write};
use lazy_static::lazy_static;
use crate::console::SbiStdout;

pub enum LogLevers {
    DISABLED,
    TRACE,
    DEBUG,
    INFO,
    WARNING,
    ERROR,
    NOTICE,
    FATAL,
}

impl LogLevers {
    pub fn to_u32(&self) -> u32 {
        match self {
            LogLevers::DISABLED => 0,
            LogLevers::TRACE => 1,
            LogLevers::DEBUG => 2,
            LogLevers::INFO => 3,
            LogLevers::WARNING => 4,
            LogLevers::ERROR => 5,
            LogLevers::NOTICE => 6,
            LogLevers::FATAL => 7,
        }
    }
}

pub enum Colors {
    BLACK = 30,
    RED = 31,
    GREEN = 32,
    YELLOW = 33,
    BLUE = 34,
    MAGENTA = 35,
    CYAN = 36,
    WHITE = 37,
    GRAY = 90,
    // YELLOW = 93,
}

impl Colors {
    fn to_u32(&self) -> u32 {
        match self {
            Colors::BLACK => 30,
            Colors::RED => 31,
            Colors::GREEN => 32,
            Colors::YELLOW => 33,
            Colors::BLUE => 34,
            Colors::MAGENTA => 35,
            Colors::CYAN => 36,
            Colors::WHITE => 37,
            Colors::GRAY => 90,
            // Colors::YELLOW => 93,
        }
    }
}

macro_rules! console_color {
    ($arg: tt) => {
        format_args!("\x1b[{}m",$arg)
    }
}

macro_rules! color_wrap {
    ($prefix: tt,$arg: tt,$suffix: tt) => {
        format_args!(
        "{}{}{}\n",
        console_color!($prefix),
        $arg,
        console_color!($suffix),
        )
    }
}

pub struct Logger {
    pub lever: LogLevers,
}

unsafe impl Sync for Logger {}

impl Logger {
    pub fn log(&self, lever: LogLevers, args: Arguments) {
        if lever.to_u32() < self.lever.to_u32() {
            return;
        }
        let c = match lever {
            LogLevers::DISABLED => Colors::GRAY,
            LogLevers::TRACE => Colors::GRAY,
            LogLevers::DEBUG => Colors::GREEN,
            LogLevers::INFO => Colors::BLUE,
            LogLevers::WARNING => Colors::YELLOW,
            LogLevers::ERROR => Colors::RED,
            LogLevers::NOTICE => Colors::BLUE,
            LogLevers::FATAL => Colors::RED,
        };
        let color_u32 = c.to_u32();
        SbiStdout.write_fmt(color_wrap!(color_u32,args,0)).unwrap();
    }

    pub fn set_lever(&mut self, lever: LogLevers) {
        self.lever = lever;
    }
    pub fn trace(&self, args: Arguments) {
        self.log(LogLevers::TRACE, args)
    }
    pub fn debug(&self, args: Arguments) {
        self.log(LogLevers::DEBUG, args)
    }
    pub fn info(&self, args: Arguments) {
        self.log(LogLevers::INFO, args)
    }
    pub fn warning(&self, args: Arguments) {
        self.log(LogLevers::WARNING, args)
    }
    pub fn error(&self, args: Arguments) {
        self.log(LogLevers::ERROR, args)
    }
    pub fn notice(&self, args: Arguments) {
        self.log(LogLevers::NOTICE, args)
    }
    pub fn fatal(&self, args: Arguments) {
        self.log(LogLevers::TRACE, args)
    }
}

lazy_static! {
    pub static ref logger: Logger= {
        let mut log=Logger{
        lever:LogLevers::DEBUG
        };
        log
    };
}

#[macro_export]
macro_rules! set_log_lever {
    ($arg:tt) => {
        $crate::log::logger.set_lever($arg);
    }
}

#[macro_export]
macro_rules! trace {
    ($fmt: literal $(, $($arg: tt)+)?) => {
        $crate::log::logger.trace(format_args!(concat!($fmt) $(, $($arg)+)?));
    }
}

#[macro_export]
macro_rules! debug {
    ($fmt: literal $(, $($arg: tt)+)?) => {
        $crate::log::logger.debug(format_args!(concat!($fmt) $(, $($arg)+)?));
    }
}

#[macro_export]
macro_rules! info {
    ($fmt: literal $(, $($arg: tt)+)?) => {
        $crate::log::logger.info(format_args!(concat!($fmt) $(, $($arg)+)?));
    }
}

#[macro_export]
macro_rules! warning {
    ($fmt: literal $(, $($arg: tt)+)?) => {
        $crate::log::logger.warning(format_args!(concat!($fmt) $(, $($arg)+)?));
    }
}

#[macro_export]
macro_rules! error {
    ($fmt: literal $(, $($arg: tt)+)?) => {
        $crate::log::logger.error(format_args!(concat!($fmt) $(, $($arg)+)?));
    }
}

#[macro_export]
macro_rules! notice {
    ($fmt: literal $(, $($arg: tt)+)?) => {
        $crate::log::logger.notice(format_args!(concat!($fmt) $(, $($arg)+)?));
    }
}

#[macro_export]
macro_rules! fatal {
    ($fmt: literal $(, $($arg: tt)+)?) => {
        $crate::log::logger.fatal(format_args!(concat!($fmt) $(, $($arg)+)?));
    }
}


// static mut GLOBAL_LOG_LEVER: LogLevers = LogLevers::DEBUG;
//
// pub fn set_global_log_lever(lever: LogLevers) {
//     unsafe { GLOBAL_LOG_LEVER = lever }
// }
//
// pub fn log(lever: LogLevers, args: Arguments) {
//     unsafe {
//         if lever.to_u32() < GLOBAL_LOG_LEVER.to_u32() {
//             return;
//         }
//     }
//     let c = match lever {
//         LogLevers::DISABLED => Colors::GRAY,
//         LogLevers::TRACE => Colors::GRAY,
//         LogLevers::DEBUG => Colors::GREEN,
//         LogLevers::INFO => Colors::BLUE,
//         LogLevers::WARNING => Colors::YELLOW,
//         LogLevers::ERROR => Colors::RED,
//         LogLevers::NOTICE => Colors::BLUE,
//         LogLevers::FATAL => Colors::RED,
//     };
//     let color_u32 = c.to_u32();
//     SbiStdout.write_fmt(color_wrap!(color_u32,args,0)).unwrap();
// }

// #[macro_export]
// macro_rules! trace {
//     ($fmt: literal $(, $($arg: tt)+)?) => {
//         $crate::log::log($crate::log::LogLevers::TRACE,format_args!(concat!($fmt) $(, $($arg)+)?));
//     }
// }
//
// #[macro_export]
// macro_rules! debug {
//     ($fmt: literal $(, $($arg: tt)+)?) => {
//         $crate::log::log($crate::log::LogLevers::DEBUG,format_args!(concat!($fmt) $(, $($arg)+)?));
//     }
// }
//
// #[macro_export]
// macro_rules! info {
//     ($fmt: literal $(, $($arg: tt)+)?) => {
//         $crate::log::log($crate::log::LogLevers::INFO,format_args!(concat!($fmt) $(, $($arg)+)?));
//     }
// }
//
// #[macro_export]
// macro_rules! warning {
//     ($fmt: literal $(, $($arg: tt)+)?) => {
//         $crate::log::log($crate::log::LogLevers::WARNING,format_args!(concat!($fmt) $(, $($arg)+)?));
//     }
// }
//
// #[macro_export]
// macro_rules! error {
//     ($fmt: literal $(, $($arg: tt)+)?) => {
//         $crate::log::log($crate::log::LogLevers::ERROR,format_args!(concat!($fmt) $(, $($arg)+)?));
//     }
// }
//
// #[macro_export]
// macro_rules! notice {
//     ($fmt: literal $(, $($arg: tt)+)?) => {
//         $crate::log::log($crate::log::LogLevers::NOTICE,format_args!(concat!($fmt) $(, $($arg)+)?));
//     }
// }
//
// #[macro_export]
// macro_rules! fatal {
//     ($fmt: literal $(, $($arg: tt)+)?) => {
//         $crate::log::log($crate::log::LogLevers::FATAL,format_args!(concat!($fmt) $(, $($arg)+)?));
//     }
// }